/*
 * Poster.java
 *
 * Created on November 19, 2006, 11:56 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package Comm.Net;

import Comm.Net.BaseData;
import Comm.Util.Exceptions.NoBarsException;
import Comm.Util.Exceptions.ServerDownException;
import Comm.Util.Exceptions.AlertException;
import Experience.ExpUI;

import Comm.Util.Logger;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Alert;

/**
 *
 * @author dmgreen
 */
public class NetThread extends Thread {
    
    BaseData myData = null;
    
    /** Creates a new instance of Poster */
    public NetThread(BaseData bd) {
        myData   = bd;
    }
    
    public void run() {
        try {
            myData.setStatus(BaseData.SENDING);
            String res = send();
             myData.setResponse(res);
             myData.setSendTime(System.currentTimeMillis());
            //Logger.getLog().addLogMessage("Result starts with: " + res.substring(0,100));
             
            myData.setStatus(BaseData.SENT);
            Logger.getLog().addLogMessage("Sample id " + myData.getUID() + " successfully uploaded!", Logger.MSG_INFO);
        }
        catch (IOException ioe){
            Logger.getLog().addLogMessage("Got an IOEexception in NetThread!: " + ioe.getMessage(), Logger.MSG_ERROR);
            myData.setStatus(BaseData.FAILED);
        }
        catch (ServerDownException sde) {
            Logger.getLog().addLogMessage("Got a ServerDownException in PostThread!: " + sde.getMessage(), Logger.MSG_ERROR);
            myData.setStatus(BaseData.FAILED);
            ExpUI.getMIDlet().showAlert("It appears that the MAHI server is down. Please notify the researchers!" +
                    "(" + sde.getMessage() + ")" );
        }
        catch (NoBarsException nbe) {
            Logger.getLog().addLogMessage("Got NoBarsException in PostThread!: " + nbe.getMessage(), Logger.MSG_ERROR);
            myData.setStatus(BaseData.FAILED);
            ExpUI.getMIDlet().showAlert("Couldn't send sample because there is no cellular service here. " +
                    "Will try again later!");
        }
        catch (AlertException ae) {
            Logger.getLog().addLogMessage("Got an AlertException in PostThread: " + ae.getMessage(), Logger.MSG_ERROR);
            // shouldi it be failed? or still unsent?
            myData.setStatus(BaseData.FAILED);
            ExpUI.getMIDlet().showAlert(ae.getMessage());
        }
        catch (Exception e) {
            Logger.getLog().addLogMessage("Got an (unanticipated) Exception in PostThread: " + e.getMessage(), Logger.MSG_ERROR);
            // shouldi it be failed? or still unsent?
            myData.setStatus(BaseData.FAILED);
        }
        
        finally { 
            //Logger.getLog().addLogMessage("NetThread JOINING!"); 
        }
        
    }
    
     public String send() throws IOException, ServerDownException, NoBarsException, AlertException, Exception {
        
        // try doing all declarations from within here ...
        HttpConnection    hc   = null;        
        DataOutputStream  dos  = null;
        DataInputStream   dis   = null; 
        
        String resp = "";
        
        try {
            Logger.getLog().addLogMessage("Opening socket to host", Logger.MSG_DEBUG);
            hc = openSocket();
            //Logger.getLog().addLogMessage("Opened socket, sending data now (hc is " + hc.toString() + ")...");

            dos = hc.openDataOutputStream();
            Logger.getLog().addLogMessage("Sending data", Logger.MSG_DEBUG);
            sendData(dos);
            //Logger.getLog().addLogMessage("Sent data");
            Logger.getLog().addLogMessage("Data sent ... getting response", Logger.MSG_DEBUG);
            int res_code = hc.getResponseCode();
            Logger.getLog().addLogMessage("Got a response code of " + res_code, Logger.MSG_DEBUG);
            if (res_code != HttpConnection.HTTP_OK) {
                //something has gone wrong with communication with the server
                //Logger.getLog().addLogMessage("Response code here is " + res_code);
                
                // what are interesting cases here?
                // 403 - forbidden
                // 500 - internal server error
                String res_msg = hc.getResponseMessage();
                Logger.getLog().addLogMessage("Got a response message of " + res_msg, Logger.MSG_DEBUG);
                
                if (res_code == HttpConnection.HTTP_FORBIDDEN) {
                    throw new AlertException("Unable to upload sample because gateway is " +
                            "rejecting requests. Please re-start MAHI!");
                }
                
                if (res_code == HttpConnection.HTTP_INTERNAL_ERROR) {
                    throw new AlertException("Server encountered an error during upload. " +
                            "Please notify researchers!");
                }
                else {
                    throw new IOException("Got a response code of \"" + res_code + "\" and a message of \"" + res_msg + "\"" );
                }
            }

            Logger.getLog().addLogMessage("Reading response", Logger.MSG_DEBUG);
            dis = hc.openDataInputStream();
            resp = readResponse(dis);
            //Logger.getLog().addLogMessage("Read response ...");
        }
        
        // i'm not even sure i need this block ...
        /*
        catch (IOException ioe)  {throw ioe;}
        catch (ServerDownException sde) {throw sde;}
        catch(NoBarsException nbe) {throw nbe;}
        catch(AlertException ae) { throw ae; }
          */
        
        finally {
            try {
                if (dis != null) {
                     dis.close(); 
                     dis = null;
                     //Logger.getLog().addLogMessage("1. Inputstream successfully closed");
                 }
            } catch (Exception e) {
               Logger.getLog().addLogMessage("Error while closing Inputstream", Logger.MSG_ERROR);
            }

            try {
                if (dos != null) {
                    dos.close(); 
                    dos = null;
                    //Logger.getLog().addLogMessage("2. DataOutputstream successfully closed");
                }
            } catch (Exception e) {
               Logger.getLog().addLogMessage("Error while closing Outputstream", Logger.MSG_ERROR);
            }

            try {
                if(hc != null) {
                       hc.close();
                       hc = null;
                       //Logger.getLog().addLogMessage("3. HttpConnection successfully closed");
                }
            } catch(IOException e) {
                Logger.getLog().addLogMessage("Error while closing HTTPConnection!", Logger.MSG_ERROR);
            }
    
            Logger.getLog().addLogMessage("Successfully cleaned up comm streams", Logger.MSG_DEBUG);
            System.gc();
            //Logger.getLog().addLogMessage("Finished in Poster.send");
        }
        
        return resp;
    }
    
     private HttpConnection openSocket() throws ServerDownException, NoBarsException, AlertException, Exception {
        
        HttpConnection myhc = null;
        boolean got_exception = false;
        
        try {
            //Logger.getLog().addLogMessage("Trying to open ModdWeb");
             myhc = (HttpConnection) Connector.open(myData.getURL()); 
                                                //Connector.READ_WRITE);
            myhc.setRequestMethod(HttpConnection.POST);
            
            /* TO PUT BACK IN */
            myhc.setRequestProperty("Content-Type", "multipart/form-data; boundary=-----frontier" );
            myhc.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.1");
            myhc.setRequestProperty("Content-Language", "en-CA");
            myhc.setRequestProperty("Connection", "close");
            
            //Logger.getLog().addLogMessage(myData.getPayload(), Logger.MSG_INFO);
            
            byte[] byteRequest = (myData.getPayload()).getBytes(); 
            myhc.setRequestProperty( "Content-Length", Integer.toString(byteRequest.length) );
            
            return myhc;
        }
        catch (IOException ioe) {
            got_exception = true;
            Logger.getLog().addLogMessage("IOException while opening HTTPConnection", Logger.MSG_ERROR);
            try {
                Logger.getLog().addLogMessage("Trying to connect to Google...", Logger.MSG_ERROR);
                HttpConnection hc2 = (HttpConnection) Connector.open("http://www.google.com");
                hc2.close();
            } catch (IOException ioe2) {
                throw new NoBarsException("");
            }
            throw new ServerDownException("Can't reach host: \"" + ioe.toString() + "\"");
        }
        
        catch (SecurityException se) {
            got_exception = true;
            throw new AlertException("Please restart the application, and press \"Yes\" when " +
                    "the phone asks you if you want to "  +
                    "\"Allow application MAHIdemo to use network and send or receive data?\"");
        }
        catch (Exception e) {
            got_exception = true;
            throw e;
        }
        
        finally {
            try {
                if (got_exception && myhc != null) {
                     myhc.close(); 
                 }
            } catch (Exception e) {
               Logger.getLog().addLogMessage("Error while closing HTTPConnection", Logger.MSG_ERROR);
            }
        }
    }
      
     private void sendData(DataOutputStream d_os) throws IOException {
        byte[] byteRequest = (myData.getPayload()).getBytes(); 
        d_os.write(byteRequest);
        //Logger.getLog().addLogMessage("Wrote data via 'write' call");
    }
    
     private String readResponse(DataInputStream d_is) throws IOException{
           
        StringBuffer sb = new StringBuffer();
             
        int c = 0;
        while (((c = d_is.read()) != -1) ) {
            sb.append((char) c);
        }
            
       return sb.toString();
    }
}
